package study;

import com.google.inject.AbstractModule;
import com.google.inject.Key;
import com.google.inject.Scope;
import org.jboss.resteasy.plugins.guice.RequestScoped;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

import javax.ws.rs.Path;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import java.util.Set;

/**
 * Created by 徐翔 on 14-3-11.
 */
public class GuiceModule extends AbstractModule {

    @Override
    protected void configure() {

        bindResteasy();
        bindPathResource();
    }

    private void bindResteasy(){
        bindScope(RequestScoped.class, new Scope()
        {
            @Override
            public <T> com.google.inject.Provider<T> scope(final Key<T> key, final com.google.inject.Provider<T> creator)
            {
                return new com.google.inject.Provider<T>()
                {
                    @SuppressWarnings("unchecked")
                    @Override
                    public T get()
                    {
                        Class<T> instanceClass = (Class<T>) key.getTypeLiteral().getType();
                        T instance = ResteasyProviderFactory.getContextData(instanceClass);

                        if (instance == null) {
                            instance = creator.get();
                            ResteasyProviderFactory.pushContext(instanceClass, instance);
                        }

                        return instance;
                    }

                    @Override
                    public String toString() {
                        return String.format("%s[%s]", creator, this);
                    }
                };
            }
        });

        bind(HttpRequest.class).toProvider(new ResteasyContextProvider<HttpRequest>(HttpRequest.class)).in(RequestScoped.class);
        bind(HttpResponse.class).toProvider(new ResteasyContextProvider<HttpResponse>(HttpResponse.class)).in(RequestScoped.class);
        bind(Request.class).toProvider(new ResteasyContextProvider<Request>(Request.class)).in(RequestScoped.class);
        bind(HttpHeaders.class).toProvider(new ResteasyContextProvider<HttpHeaders>(HttpHeaders.class)).in(RequestScoped.class);
        bind(UriInfo.class).toProvider(new ResteasyContextProvider<UriInfo>(UriInfo.class)).in(RequestScoped.class);
        bind(SecurityContext.class).toProvider(new ResteasyContextProvider<SecurityContext>(SecurityContext.class)).in(RequestScoped.class);
    }
    private void bindPathResource(){
        Reflections reflections = new Reflections(new ConfigurationBuilder()
                .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("study")))
                .setUrls(ClasspathHelper.forPackage("study"))
                .setScanners(new TypeAnnotationsScanner(), new SubTypesScanner()));
        Set<Class<?>> pathClass = reflections.getTypesAnnotatedWith(Path.class);
        for (Class<?> resource : pathClass){
            bind(resource);
        }
    }




    private static class ResteasyContextProvider<T> implements com.google.inject.Provider<T> {

        private final Class<T> instanceClass;

        public ResteasyContextProvider(Class<T> instanceClass)
        {
            this.instanceClass = instanceClass;
        }

        @Override
        public T get() {
            return ResteasyProviderFactory.getContextData(instanceClass);
        }
    }

}
